啟動流程 & 程式碼

1. 名詞定義

縮寫 描述
GM App Gateway Management app
WKN Well-Know Name,有別於About的建立session方式
ACL Access Control List
Config file 描述Alljoyn router的Policy(Allow or Deny)
SLS Sessionless Signal

2. Connector Code

  1. Initialize Bus At tachment:Start & Connect
BusAttachment* bus = new BusAttachment("ConnectorApp", true);
bus->Start();
bus->Connect();
  1. Initialize authentication:EnablePeerSecurity這個函數是用來啟動身分驗證與加密機制,使用前需要先Start
keyListener.setPassCode("000000");

String keystore = "/opt/alljoyn/apps/" + wellknownName + "/store/.alljoyn_keystore.ks";

bus.EnablePeerSecurity("ALLJOYN_PIN_KEYX ALLJOYN_SRP_KEYX ALLJOYN_ECDHE_PSK", &keyListener, keystore.c_str(), false);

這裡所出現的keyListener是一種自定類別,繼承自AuthListenerclass SrpKeyXListener : public ajn::AuthListener

SrpKeyXListener keyListener;

AuthListener為啟動驗證機制時,負責傳達Password或其他與驗證機制相關的Class。

繼承AuthListener時,有幾種virtual method可以實作,其中比較常用的有RequestCredentials/AuthenticationComplete

virtual bool RequestCredentials (const char *authMechanism, const char 
*peerName, uint16_t authCount, const char *userName, uint16_t credMask, >>Credentials &credentials)
virtual void     AuthenticationComplete (const char *authMechanism, const >>char *peerName, bool success)=0

以下用SrpKeyXListener改寫的內容做為範例: 首先是RequestCredentials

bool SrpKeyXListener::RequestCredentials(const char* authMechanism, const char* authPeer,uint16_t authCount, const char* userId, uint16_t credMask, Credentials& creds)
{
    std::cout << "RequestCredentials for authenticating " << authPeer << " using mechanism " << authMechanism << std::endl;
    if (strcmp(authMechanism, "ALLJOYN_SRP_KEYX") == 0 || strcmp(authMechanism, "ALLJOYN_PIN_KEYX") == 0 || strcmp(authMechanism, "ALLJOYN_ECDHE_PSK") == 0) {
        if (credMask & AuthListener::CRED_PASSWORD) {
            if (authCount <= 3) {
                qcc::String passCodeFromGet;
                if (m_GetPassCode) {
                    m_GetPassCode(passCodeFromGet);
                }
                std::cout << "RequestCredentials setPasscode to " << (m_GetPassCode ? passCodeFromGet.c_str() : m_PassCode.c_str()) << std::endl;
                creds.SetPassword(m_GetPassCode ? passCodeFromGet.c_str() : m_PassCode.c_str());
                return true;
            } else {
                return false;
            }
        }
    }
    return false;
}

其中CredentialsAuthListener的Inner class,作為傳遞認證資訊的關鍵角色。

再來是AuthenticationComplete

void SrpKeyXListener::AuthenticationComplete(const char* authMechanism, const char* authPeer, bool success)
{
    std::cout << "Authentication with " << authMechanism << (success ? " was successful" : " failed") << std::endl;
}

此處只有一行cout,表明認證結果。

當Interface的secure設為True,第一次調用此Interface下的任何member,都會產生認證要求。

以下是上述Code的認證執行輸出:

RequestCredentials for authenticating org.alljoyn.GWAgent.GMApp using mechanism ALLJOYN_ECDHE_PSK RequestCredentials setPasscode to 000000 Authentication with ALLJOYN_ECDHE_PSK was successful

  1. Initialize Connector
class MyApp : public GatewayConnector

MyApp myApp(&bus, wellknownName.c_str());
myApp.init();

繼承GatewayConnector時,有幾項Method需要實作。

virtual void shutdown() {…}
virtual void mergedAclUpdated() {…}
void receiveGetMergedAclAsync(QStatus unmarshalStatus,GatewayMergedAcl* response) {…}

基本上到目前為止,就已經完成一個Connector了。接著只需要跟Cloud互動,並在互動過程中適時的呼叫myApp.updateConnectionStatus(...)回報給GM App目前與雲端的連接狀態。GM App收到後,會發Signal給ControlerControler收到後會呼叫GM AppInterface的Method取得狀態。

GatewayConnector這個Class透過WKN取得GM App的ProxyBusObject,其內部有2個Method與3個Signal,需要RegisterSignalHandler

 ifc->AddMethod("GetMergedAcl", NULL,  "a(obas)a(saya(obas))", "exposedServices,remotedApps");
ifc->AddMethod("UpdateConnectionStatus", "q", NULL, "connectionStatus", MEMBER_ANNOTATE_NO_REPLY);
ifc->AddSignal("MergedAclUpdated", NULL, NULL);
ifc->AddSignal("ShutdownApp", NULL, NULL);

3. Manifest.xml

Build好Connector後的下一個工作,就是建置Manifest.xml了。Manifest.xml描述Connector的Service、感興趣的Interface、Connector執行時的參數傳入。

是之後Control App用以建立ACL的依據。

以下為Manifest.xml範例結構。

<manifest xmlns="http://www.alljoyn.org/gateway/manifest">
    <connectorId>dummyapp1</connectorId>
    <friendlyName>dummyAppOne</friendlyName>
    <packageName>dummyAppOne_0.0.1-1_ar71xx.ipk</packageName>
    <version>0.0.1</version>
    <minAjSdkVersion>3.4.0</minAjSdkVersion>
    <exposedServices>
        <object name="EmergencyNotifications">
            <path>/emergency</path>
            <isPrefix>false</isPrefix>
            <interfaces>
                <interface name="NotificationInterface">org.alljoyn.Notification</interface>
            </interfaces>                    
        </object>
        <object name="WarningNotifications">
            <path>/warning</path>
            <isPrefix>false</isPrefix>            
            <interfaces>
                <interface name="NotificationInterface">org.alljoyn.Notification</interface>
            </interfaces>
        </object>
    </exposedServices>
    <remotedServices>
        <object name="AllObjectPaths">
            <path>/</path>
            <isPrefix>true</isPrefix>            
            <interfaces>            
                <interface name="NotificationInterface">org.alljoyn.Notification</interface>
                <interface name="AboutInterface">org.alljoyn.About</interface>
                <interface name="AboutIcon">org.alljoyn.Icon</interface>
                <interface name="NotificationSuperInterface">org.alljoyn.NotificationSuper</interface>
                <interface name="ConfigInterface">org.alljoyn.Config</interface>
            </interfaces>                
        </object>
    </remotedServices>
    <executionInfo>
        <executable>alljoyn-gwconnectorsample</executable>
        <env_variables>            
            <variable name="LD_LIBRARY_PATH">/opt/alljoyn/apps/dummyapp1/lib</variable>
            <variable name="ER_DEBUG">7</variable>
            <variable name="INTERACTIVE_OFF">1</variable>
            <variable name="TWITTER_SCRIPT">postTweet.sh</variable>
        </env_variables>
        <arguments>
        </arguments>
    </executionInfo>    
</manifest>

4. 安裝Connector

有了Build好的ConnectorManifest.xml以後,接著就是安裝/移除Connector了。

安裝的第一步就是將lib、bin、Manifest.xml依照下列格式擺放。 Alt text

之後將整包壓縮成一個tar檔案。

tar czf dummyApp1.tar.gz -C gatewayConnector/tar
Alt text
Image 1 - Alt text

接著透過官方提供的installPackage.sh/removePackage.sh進行安裝/移除

./installPackage.sh dummyApp1.tar.gz

installPackage.sh所做的事情很單純, 只是將tar檔裡的東西轉移到/opt/alljoyn/apps/$connectorId之中,然後創造一個Linux User,並將store這個Folder的擁有者,轉移到新創的Linux User下

baseDir=/opt/alljoyn
manifestFile=$tmpDir/Manifest.xml
appBinDir=$tmpDir/bin
connectorId=$(grep "<connectorId>" $manifestFile | sed -e "s/ *<connectorId>//" | sed -e "s/<\/connectorId *>//")
connectorAppDir=$baseDir/apps/$connectorId

if [ $? -ne 0 ]; then
    useradd $connectorId || exit 22
    createdUser=1
fi

chown -R "$connectorId" "$pkgInstallDir/store" || exit 23
chmod -R a+rx "$pkgInstallDir/bin" || exit 24
chmod -R a+rx "$pkgInstallDir/lib" || exit 25

經過上面安裝後,就會看到/opt/alljoyn/apps/$connectorId目錄,結構如下。

此時acls Folder內無東西。可以透過shell自行創造,或是啟動GM AppController App後,透過Contorller App建立。

Alt text

5. 啟動

5.1. 啟動Router

在啟動GM AppConnectors之前,先確定alljoyn-daemon是否已經安裝並啟動。

先確認是否Build好的alljoyn-daemon放在/usr/bin/中,並寫好alljoyn.init放在/etc/init.d/alljoyn之中。之後執行service alljoyn start

以下為alljoyn.init的start script

start() {
  if [ -f $PIDFILE ] && kill -0 $(cat $PIDFILE); then
    echo 'Service already running' >&2
    return 1
  fi
  echo 'Starting service…' >&2
  local CMD="$SCRIPT --config-file=/opt/alljoyn/alljoyn-daemon.d/config.xml &> \"$LOGFILE\" & echo \$!"
  su -c "$CMD" $RUNAS > "$PIDFILE"
  echo 'Service started' >&2
}

執行時所帶的參數--config-file指出Router Config Policy的位置,此例為/opt/alljoyn/alljoyn-daemon.d/config.xml

注意Config File內,要include GM App執行時動態改變的Policy File,此例為gwagent-config.xml

<busconfig>
    <type>alljoyn</type>
    <property name="router_advertisement_prefix">org.alljoyn.BusNode</property>
    <listen>unix:abstract=alljoyn</listen>
    <listen>tcp:r4addr=0.0.0.0,r4port=0</listen>
    <limit name="auth_timeout">5000</limit>

    <limit name="max_incomplete_connections">16</limit>
    <limit name="max_completed_connections">100</limit>
    <limit name="max_untrusted_clients">100</limit>
    <flag name="restrict_untrusted_clients">false</flag>

    <ip_name_service>
        <property interfaces="*"/>
        <property disable_directed_broadcast="false"/>
        <property enable_ipv4="true"/>
        <property enable_ipv6="true"/>
    </ip_name_service>
    <include>/opt/alljoyn/alljoyn-daemon.d/gwagent-config.xml</include>
</busconfig>

Config File內所有可用的的Tag,與每個Tag的說明,請參閱以下網址。 XML Schema Routing Node Configuration File

確認完成後,執行Router:service alljoyn start

5.2. 啟動GM App

確認Config File 與start alljoyn-daemon以後,對於GM App我們也依法照做一次。

將Build好的alljoyn-gwagent放在/usr/bin/中,並寫好alljoyn-gwagent.init放在/etc/init.d/alljoyn-gwagent之中。之後執行service alljoyn-gwagent start

以下為alljoyn-gwagent.init的start script

start() {
  if [ -f $PIDFILE ] && kill -0 $(cat $PIDFILE); then
    echo 'Service already running' >&2
    return 1
  fi
  echo 'Starting service…' >&2
  local CMD="$SCRIPT &> \"$LOGFILE\" & echo \$!"
  su -c "$CMD" $RUNAS > "$PIDFILE"
  echo 'Service started' >&2
}

注意:雖然此例沒有使用,但事實上可以帶入參數--gwagent-policy-file指出GM App執行時動態產生的Config File,以及--apps-policy-dir指出根據ACL產生的Config File Folder

以下為GM App程式碼片段

String policyFileOption = "--gwagent-policy-file=";
String appsPolicyDirOption = "--apps-policy-dir=";

   for (int i = 1; i < argc; i++) {
        String arg(argv[i]);
        if (arg.compare(0, policyFileOption.size(), policyFileOption) == 0) {
            String policyFile = arg.substr(policyFileOption.size());
            QCC_DbgPrintf(("Setting gatewayPolicyFile to: %s", policyFile.c_str()));
            gatewayMgmt->setGatewayPolicyFile(policyFile.c_str());
        }
        if (arg.compare(0, appsPolicyDirOption.size(), appsPolicyDirOption) == 0) {
            String policyDir = arg.substr(appsPolicyDirOption.size());
            QCC_DbgPrintf(("Setting appsPolicyDir to: %s", policyDir.c_str()));
            gatewayMgmt->setAppPolicyDir(policyDir.c_str());
        }
    }

例如:

start() {
service_start /usr/bin/alljoyn-gwagent `--gwagent-policy-file`=/etc/alljoyn/gwagent/gwagent.conf `--apps-policy-dir`=/etc/alljoyn/gwagent-apps
}

如果沒有特別指明,則Default gwagent-policy-file/opt/alljoyn/alljoyn-daemon.d/gwagent-config.xml apps-policy-dir/opt/alljoyn/alljoyn-daemon.d/apps

static const qcc::String GATEWAY_POLICIES_DIRECTORY = "/opt/alljoyn/alljoyn-daemon.d";

GatewayRouterPolicyManager::GatewayRouterPolicyManager() : m_AboutListenerRegistered(false), m_AutoCommit(false),
    m_gatewayPolicyFile(GATEWAY_POLICIES_DIRECTORY + "/gwagent-config.xml"), m_appPolicyDirectory(GATEWAY_POLICIES_DIRECTORY + "/apps")
{
}

下圖為此範例的目錄結構: Alt text config.xmlAlt text gwagent-config.xmlAlt text apps-policy-dir內的dummyapp1.xmlAlt text

確認完成後,執行GM App:service alljoyn-gwagent start

5.3. 驗證

透過ps -ef | grep alljoyn指令驗證 Alt text

5.4. 目錄結構

/opt/alljoyn下的樹狀結構: Alt text

5.5. Controller App畫面

進入搜尋到的GM AppAlt text

進入Connector's acl列表 Alt text

允許Connector的服務: Alt text

含有此Connector感興趣的Interface的Device: Alt text

允許Connector存取此Device: Alt text

ACL產生: Alt text

同時產生Config Policy: Alt text

© 2017 Trashman all right reserved,powered by Gitbook修訂時間: 2024-10-14 03:41:00

results matching ""

    No results matching ""